package Model.Game;

import java.io.* ;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.Vector;

import javax.swing.Timer;

import Model.Beat.BeatModelInterface;
import View.BPMObserver;
import View.BeatObserver;

public class GameModel implements BeatModelInterface,Runnable{
	
	ArrayList<Object> beatObservers = new ArrayList<Object>();
	ArrayList<Object> bpmObservers = new ArrayList<Object>();
	ArrayList<String> users = new ArrayList<String>() ;
	ArrayList<Integer> scores = new ArrayList<Integer>() ;

	String path = ".\\scores.txt" ; 
	String userName ; 
	Scanner reader ;
	BufferedReader rFile ;
	BufferedWriter wFile ;
	ListIterator<Integer> scoreIter ;
	ListIterator<String> userIter ; 
    
	private int clicks;
    private boolean b;
    private boolean timeLimit;
    private boolean dontBeat;
    private int currentTime;
    
    private Thread thread;
    Timer timer;
    Timer timer2;
    
    public GameModel() {
		this.b=false;
		this.timeLimit=false;
		this.dontBeat = true;
		this.currentTime = 10;
    	readCSV();
		thread = new Thread(this);
		thread.start();
		
		timer = new Timer(10000, new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e) {
				timeLimit = true;		
			}
		});
		
		timer2 = new Timer(1000, new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e) {
				if(currentTime != 0){
					currentTime--;
					notifyBPMObservers();
				} else{
					timer2.stop();
					insertResultInScores(userName) ; 
				}
			}	
		});
		
    }



	private void readCSV() {
		try {
			rFile = new BufferedReader(new FileReader(path)) ;
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
    	
		String line = ""; 
			try {
				while((line = rFile.readLine()) != null){
					reader = new Scanner(line) ;
					reader.useDelimiter(",");
					users.add(reader.next()) ; 
					scores.add(Integer.parseInt(reader.next().trim())) ; 
				}
			} catch (NumberFormatException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
	}
    	
    

	@Override
	public void run() {
		try{
		while(true){
			if(b){
				if(!timeLimit){
					if(dontBeat){
						notifyBeatObservers();
					}
					notifyBPMObservers();
				}
				b=false;
			}
			Thread.sleep(10);
		}}catch(InterruptedException ex){
			;;
		}
		
	}
	
	public void reset(){
		this.currentTime = 10;
		notifyBPMObservers();
		this.clicks=0;
		this.timeLimit = false;
		dontBeat = false;
		timer.stop();
		timer2.stop();
		this.b=true;
	}


	private void notifyBPMObservers() {
		for(int i= 0; i< bpmObservers.size();i++){
			((BPMObserver)bpmObservers.get(i)).updateBPM();
		}
	}



	public void notifyBeatObservers() {
		for(int i = 0; i < beatObservers.size(); i++) {
			BeatObserver observer = (BeatObserver)beatObservers.get(i);
			observer.updateBeat();
		}
	}


	@Override
	public void initialize() {
	}

	@Override
	public void on() {
		this.clicks=0;
		
	}

	@Override
	public void off() {
		this.clicks=0;
		
	}

	@Override
	public void setBPM(int bpm) {
		this.clicks=bpm;
		
	}
	
	public void increaseBPM(){
		if(clicks == 0){
			timer2.start();
			timer.start();
		} 
		dontBeat = true;
		if(!timeLimit)
			this.clicks++;
		this.b=true;
	}

	@Override
	public int getBPM() {
		return this.clicks;
	}
	
	public int getCurrentTime(){
		return this.currentTime;
	}

	public void registerObserver(BeatObserver o) {
		beatObservers.add(o);
	}

	public void removeObserver(BeatObserver o) {
		int i = beatObservers.indexOf(o);
		if (i >= 0) {
			beatObservers.remove(i);
		}
	}


	public void registerObserver(BPMObserver o) {
		bpmObservers.add(o);
	}

	public void removeObserver(BPMObserver o) {
		int i = bpmObservers.indexOf(o);
		if (i >= 0) {
			bpmObservers.remove(i);
		}
	}
	
	public void insertResultInScores(String userName ) {
		scoreIter = scores.listIterator(); 
		userIter = users.listIterator() ; 
		boolean aux = true ;
		while (scoreIter.hasNext()){
			userIter.next(); 
			scoreIter.next(); 
		}
		
		while (scoreIter.hasPrevious()){
			userIter.previous() ; 
			if ( scoreIter.previous() < getBPM() ){
				scoreIter.add(getBPM()) ; 
				userIter.add(userName) ;
				aux = false  ;
				break ; 
			}
		}
		if(aux){ 
			scores.add(0,getBPM()) ; 
			users.add(0,userName) ;
		}
		printInCSV() ;
	}



	private void printInCSV() {
		try {
			wFile = new BufferedWriter(new FileWriter(path)) ;
		} catch (IOException e) {
			e.printStackTrace();
		} 
		String aux ; 
		scoreIter = scores.listIterator(); 
		userIter = users.listIterator() ; 
		while( scoreIter.hasNext() ){
			aux= String.format( "%s,%d\n", userIter.next(),scoreIter.next()) ; 
			try {
				wFile.write(aux) ;
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		
	}
	
	public void setUserName(String userName) { 
		this.userName = userName ; 
	}



	public Vector<Vector<Object>> genTableData() {
		Vector<Vector<Object>> o = new Vector<Vector<Object>> () ;  
		Vector<Object> aux ;
		scoreIter = scores.listIterator() ; 
		userIter = users.listIterator() ; 
		while ( scoreIter.hasNext()){
			scoreIter.next(); 
			userIter.next(); 
		}
		for(int i = 0 ; i <scores.size()  && userIter.hasPrevious() && scoreIter.hasPrevious(); i++ ){
				aux = new Vector<Object> () ; 
				aux.add(0,userIter.previous()) ;
				aux.add(1,scoreIter.previous()) ; 
				o.add(i,aux) ; 
		}
		return o ; 
	}
	
}
